﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TDGenerator
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public string CurrentFileTargetPath { get; set; }
        FileDetails details = new FileDetails();

        public MainWindow()
        {
            InitializeComponent();
        }

        private void btnGenerateDescription_Click(object sender, RoutedEventArgs e)
        {
            Progress<string> prog = new Progress<string>(b => txtStatus.Text = b);
            details.FullFilePath = CurrentFileTargetPath;
            FileInfo fi = new FileInfo(CurrentFileTargetPath);
            details.FileName = fi.Name;
            details.FileExtension = fi.Extension;
            Task<bool>.Factory.StartNew(() =>
            {
                return LoadDetails(details, prog) && GetScreenshots(details, prog);
            }).ContinueWith(b =>
                {
                    if(!b.Result)
                    {
                        txtStatus.Text = "An Error was encountered. Sorry!";
                        return;
                    }                    
                    txtResults.Text = GenerateBBCode(details);                    
                    foreach (var item in details.ScreenGrabs)
                    {
                        System.Windows.Controls.Image img = new System.Windows.Controls.Image();
                        img.Source = item;
                        stackImages.Children.Add(img);
                    }                    
                    txtStatus.Text = "Finished.";
                }, TaskScheduler.FromCurrentSynchronizationContext());
        }

        private void btnBrowseToMovieFile_Click(object sender, RoutedEventArgs e)
        {
            using (System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog())
            {
                ofd.Multiselect = false;
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK && ofd.CheckFileExists)
                {
                    CurrentFileTargetPath = ofd.FileName;
                    btnGenerateDescription.Visibility = System.Windows.Visibility.Visible;
                }
            }
        }

        private static bool LoadDetails(FileDetails mediaFile, IProgress<string> pro)
        {
            try
            {
                if (mediaFile.FullFilePath.Length == 0)
                    return false;
                pro.Report("Loading MediaInfo...");
                MediaInfo mi = new MediaInfo();
                pro.Report("MediaInfo Loaded, Opening File...");
                mi.Open(mediaFile.FullFilePath);
                pro.Report("File Opened, Reading...");
                mi.Option("Complete");
                mediaFile.MediaSummary = mi.Inform();
                mediaFile.Format = mi.Get(StreamKind.General, 0, "Format");
                double sz = 0;
                double.TryParse(mi.Get(0, 0, "FileSize"), out sz);
                mediaFile.FileSize = string.Format("{0} MB", (sz / 1024.0 / 1024.0).ToString("0.00"));
                double dura = 0.0;
                double.TryParse(mi.Get(0, 0, "Duration"), out dura);
                mediaFile.Duration = dura;
                mediaFile.DurationInMinutes = mi.Get(0, 0, "Duration/String3");
                mediaFile.OverallBitrate = mi.Get(StreamKind.General, 0, "OverallBitRate/String");
                mediaFile.EncodingApplication = mi.Get(StreamKind.General, 0, "Encoded_Application");
                mediaFile.EncodedDate = mi.Get(StreamKind.General, 0, "Encoded_Date");
                #region Subtitles
                StringBuilder subtitlesResult = new StringBuilder();
                int subCount = 0;
                int.TryParse(mi.Get(StreamKind.Text, 0, "StreamCount"), out subCount);
                if (subCount > 0)
                {
                    StringBuilder sbLang = new StringBuilder();
                    for (int i = 0; i < subCount; i++)
                    {
                        string lang = mi.Get(StreamKind.Text, i, "Language/String");
                        if (!string.IsNullOrEmpty(lang))
                        {
                            sbLang.Append(lang);
                            if (i < subCount - 1)
                                sbLang.Append(", ");
                        }
                    }
                    if (!string.IsNullOrEmpty(sbLang.ToString()))
                    {
                        subtitlesResult.Append(sbLang.ToString());
                    }
                    else
                    {
                        subtitlesResult.Append("N/A");
                    }
                }
                else
                {
                    subtitlesResult.Append("None");
                }
                #endregion
                mediaFile.Subtitles = subtitlesResult.ToString();
                mediaFile.Format = mi.Get(StreamKind.Video, 0, "Format");
                mediaFile.Codec = mi.Get(StreamKind.Video, 0, "Encoded_Library");
                mediaFile.AspectRatio = mi.Get(StreamKind.Video, 0, "DisplayAspectRatio/String");
                mediaFile.Bitrate = mi.Get(StreamKind.Video, 0, "BitRate/String");
                mediaFile.FrameRate = mi.Get(StreamKind.Video, 0, "FrameRate/String");
                mediaFile.Height = mi.Get(StreamKind.Video, 0, "Height");
                mediaFile.Width = mi.Get(StreamKind.Video, 0, "Width");
                mediaFile.Resolution = string.Format("{0}x{1}", mediaFile.Width, mediaFile.Height);
                mediaFile.AudioBitrate = mi.Get(StreamKind.Audio, 0, "BitRate/String");
                mediaFile.AudioChannels = mi.Get(StreamKind.Audio, 0, "Channel(s)/String");
                mediaFile.AudioCodec = mi.Get(StreamKind.Audio, 0, "CodecID/Hint");
                if (string.IsNullOrEmpty(mediaFile.AudioCodec))
                    mediaFile.AudioCodec = mi.Get(StreamKind.Audio, 0, "CodecID/Info");
                if (string.IsNullOrEmpty(mediaFile.AudioCodec))
                    mediaFile.AudioCodec = mi.Get(StreamKind.Audio, 0, "CodecID");
                mediaFile.AudioFormat = mi.Get(StreamKind.Audio, 0, "Format");
                mediaFile.AudioSamplingRate = mi.Get(StreamKind.Audio, 0, "SamplingRate/String");
                mi.Close();
                pro.Report("Finished Reading");
                return true;
            }
            catch (Exception)
            {
                pro.Report("An Error Occured Reading Info");
                return false;
            }
        }

        private static string GenerateBBCode(FileDetails mediaFile)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(string.Format("File: {0}", mediaFile.FileName));
            sb.AppendLine(string.Format("Size: {0}, Duration: {1}, Average bitrate: {2}", mediaFile.FileSize, mediaFile.DurationInMinutes, mediaFile.OverallBitrate));
            sb.AppendLine(string.Format("Video: {0}, {1}, {2}, {3}", mediaFile.Codec, mediaFile.Resolution, mediaFile.Bitrate, mediaFile.FrameRate));
            sb.AppendLine(string.Format("Audio: {0}, {1}, {2}, {3}", mediaFile.AudioCodec, mediaFile.AudioSamplingRate, mediaFile.AudioChannels, mediaFile.AudioBitrate));

            return sb.ToString();
        }

        /// <summary>
        /// Grab 3 screen captures as samples. We're going to pipe them into memory to minimize write permission issues.
        /// </summary>
        /// <param name="mediaFile">Make sure your path is initalized</param>
        /// <returns></returns>
        private static bool GetScreenshots(FileDetails mediaFile, IProgress<string> pro)
        {
            try
            {
                int timeSlice = (int)(mediaFile.Duration / ((3 + 1) * 1000));
                
                for (int i = 0; i < 3; i++)
                {
                    int takePicHere = timeSlice * (i + 1);
                    string parameters = string.Format("-v quiet -ss {0} -i \"{1}\" -an -f image2 -vframes 1 pipe:", takePicHere, "\"" + mediaFile.FullFilePath + "\"");
                    pro.Report("Extracting Capture " + i);
                    var processInfo = new ProcessStartInfo();
                    processInfo.FileName = "ffmpeg.exe";
                    processInfo.Arguments = parameters;
                    processInfo.LoadUserProfile = false;
                    processInfo.CreateNoWindow = true;
                    processInfo.UseShellExecute = false;
                    processInfo.RedirectStandardOutput = true;

                    using (var process = new Process())
                    {
                        process.StartInfo = processInfo;
                        process.Start();
                        byte[] buffer = new byte[32768];
                        process.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length);
                        
                        using (MemoryStream ms = new MemoryStream(buffer))
                        {
                            BitmapImage bit = new BitmapImage();
                            bit.BeginInit();
                            bit.CacheOption = BitmapCacheOption.OnLoad;
                            bit.StreamSource = ms;
                            bit.EndInit();
                            bit.Freeze();// Need to do this to prevent cross thread problems with display. Shocking eh?
                            mediaFile.ScreenGrabs.Add(bit);
                        }
                    }
                }
            }
            catch (Exception)
            {
                return false;
            }

            return true;
        }

        //http://api.themoviedb.org/3/search/movie?api_key=2c50a994de5291887a4e062edd229a72&query=hobbit
        private void btnSelectMovie_Click(object sender, RoutedEventArgs e)
        {           
            const string goTo = @"http://api.themoviedb.org/3/search/movie?api_key=2c50a994de5291887a4e062edd229a72&query=";
            using (WebClient wc = new WebClient())
            {
                wc.Headers.Add("Accept", "application/json");
                var foo = wc.DownloadString(goTo+txtMovieName);
                var searchResults = ServiceStack.Text.JsonSerializer.DeserializeFromString<TmdbMovieSearchResults>(foo);
                var results = searchResults.results ?? new List<TmdbMovieSearchResult>();
                SelectionWindow win = new SelectionWindow(results);
                win.ShowDialog();                
            }
        }
    }
}
